package com.qys.livesMall.anchor.service.impl;

import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.qys.livesMall.anchor.enums.AnchorApplyStatusEnum;
import com.qys.livesMall.anchor.enums.AnchorMessageEnum;
import com.qys.livesMall.anchor.mapper.*;
import com.qys.livesMall.anchor.model.dto.H2AnchorEditDTO;
import com.qys.livesMall.anchor.model.entity.*;
import com.qys.livesMall.anchor.model.vo.AnchorIncomeInformationVO;
import com.qys.livesMall.anchor.model.vo.AppAnchorVO;
import com.qys.livesMall.anchor.model.vo.H2AnchorVO;
import com.qys.livesMall.anchor.model.vo.lives.app.SettlementDataVO;
import com.qys.livesMall.anchor.service.AnchorLivesRoomService;
import com.qys.livesMall.anchor.service.H2AnchorService;
import com.qys.livesMall.app.user.model.entity.AppUserConcern;
import com.qys.livesMall.app.user.model.entity.H2AppUser;
import com.qys.livesMall.app.user.service.AppUserConcernService;
import com.qys.livesMall.app.user.service.IH2AppUserService;
import com.qys.livesMall.cache.RedisCache;
import com.qys.livesMall.common.enums.LanguageEnum;
import com.qys.livesMall.common.exception.QysException;
import com.qys.livesMall.common.utils.MessageUtils;
import com.qys.livesMall.finance.enums.AccountBusinessTypeEnum;
import com.qys.livesMall.finance.mapper.FinanceUserAccountDetailMapper;
import com.qys.livesMall.finance.model.dto.FinancePayDTO;
import com.qys.livesMall.finance.model.entity.user.FinanceUserAccountDetail;
import com.qys.livesMall.finance.service.FinanceBusinessService;
import com.qys.livesMall.finance.util.BusinessNoUtil;
import com.qys.livesMall.framework.utils.SecurityUtils;
import com.qys.livesMall.framework.view.BaseQuery;
import com.qys.livesMall.open.mail.AsyncMailClient;
import com.qys.livesMall.open.mail.modal.MailM;
import com.qys.livesMall.shop.constants.OrderStatus;
import com.qys.livesMall.shop.mapper.ShopOrderSettlementInfoMapper;
import com.qys.livesMall.shop.mapper.ShopOrderSkuMapper;
import com.qys.livesMall.shop.mapper.ShopSellTaskMapper;
import com.qys.livesMall.shop.modal.entity.ShopOrderSettlementInfo;
import com.qys.livesMall.shop.modal.entity.ShopOrderSku;
import com.qys.livesMall.shop.modal.entity.ShopSellTask;
import com.qys.livesMall.system.service.SysLanguageTextService;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.common.TemplateParserContext;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalTime;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * 主播表(H2Anchor)表服务实现类
 *
 * @author makejava
 * @since 2023-06-17 09:35:51
 */
@Slf4j
@Service("h2AnchorService")
public class H2AnchorServiceImpl extends ServiceImpl<H2AnchorMapper, H2Anchor> implements H2AnchorService {

    @Resource
    private H2AnchorMapper anchorMapper;
    @Resource
    private H2AnchorApplyMapper anchorApplyMapper;

    @Resource
    private IH2AppUserService appUserService;

    @Resource
    private AsyncMailClient asyncMailClient;

    @Resource
    private RedisCache redisCache;
    @Resource
    private AppUserConcernService appUserConcernService;
    @Resource
    private IH2AppUserService ih2AppUserService;

    @Resource
    private AnchorLivesGiftRecordMapper anchorLivesGiftRecordMapper;
    @Resource
    private FinanceUserAccountDetailMapper financeUserAccountDetailMapper;
    @Resource
    private AnchorLivesSessionMapper livesSessionMapper;
    @Resource
    private ShopOrderSettlementInfoMapper shopOrderSettlementInfoMapper;
    @Resource
    private ShopOrderSkuMapper shopOrderSkuMapper;
    @Resource
    private AnchorSellTaskMapper anchorSellTaskMapper;
    @Resource
    private ShopSellTaskMapper shopSellTaskMapper;
    @Resource
    private AnchorRewardConfigMapper anchorRewardConfigMapper;
    @Resource
    private AnchorLivesRoomService anchorLivesRoomService;
    @Resource
    private FinanceBusinessService financeBusinessService;

    @Resource
    private SysLanguageTextService languageTextService;

    @Override
    public IPage<AppAnchorVO> anchorList(BaseQuery dto) {
        Page<AppAnchorVO> page = new Page<>();
        page.setCurrent(dto.getPageNum());
        page.setSize(dto.getPageSize());

        if (SecurityUtils.getLoginUser()==null){
            dto.setId(null);
        }else {
            dto.setId(String.valueOf(SecurityUtils.getUserId()));
        }
        dto.setPageNum((dto.getPageNum() - 1) * dto.getPageSize());
        List<AppAnchorVO> list = anchorMapper.selectAnchorList(dto, false);
        if (CollectionUtils.isEmpty(list)) {
            return page;
        }
        List<AppAnchorVO> anchorList = anchorMapper.selectAnchorList(dto, true);
        page.setRecords(anchorList);
        page.setTotal(anchorList.size());
        return page;
    }

    @Override
    public AppAnchorVO getAnchorInfo(Long userId) {
        Wrapper<H2Anchor> queryWrapper = Wrappers.<H2Anchor>lambdaQuery().eq(H2Anchor::getUserId, userId);
        H2Anchor h2Anchor = getOne(queryWrapper);
        if (null == h2Anchor) {
            throw new QysException(AnchorMessageEnum.NO_DATA);
        }

        H2AnchorApply anchorApply = anchorApplyMapper.selectOne(Wrappers.<H2AnchorApply>lambdaQuery()
                .eq(H2AnchorApply::getUserId, userId)
                .ne(H2AnchorApply::getStatus, AnchorApplyStatusEnum.FAIL.getCode()));

        AppAnchorVO appAnchorVO = new AppAnchorVO();
        appAnchorVO.setAnchorName(h2Anchor.getAnchorName());
        appAnchorVO.setAnchorAvatar(anchorApply.getAvatar());
        appAnchorVO.setUserId(userId);
        appAnchorVO.setUserRandomId(h2Anchor.getId());
        appAnchorVO.setCarNum(h2Anchor.getCarNum());
        appAnchorVO.setCarBefore(h2Anchor.getCarBefore());
        appAnchorVO.setCarAfter(h2Anchor.getCarAfter());
        appAnchorVO.setEmail(h2Anchor.getEmail());
        appAnchorVO.setPhone(h2Anchor.getPhone());

        List<AppUserConcern> followersList = appUserConcernService.getUserConcerns(userId);
        Integer followers=CollectionUtils.isEmpty(followersList)?0:followersList.size();
        appAnchorVO.setFollowers(followers);

        H2AppUser h2AppUser=ih2AppUserService.getById(userId);
        if (null != h2AppUser){
            appAnchorVO.setNewUserRandomId(h2AppUser.getUserRandomId());
            appAnchorVO.setNickName(h2AppUser.getNickName());
        }
        LambdaQueryWrapper<AnchorLivesGiftRecord> giftambdaQuery=new LambdaQueryWrapper<>();
        giftambdaQuery.in(AnchorLivesGiftRecord::getToAnchorId,h2Anchor.getId());
        List<AnchorLivesGiftRecord> list=anchorLivesGiftRecordMapper.selectList(giftambdaQuery);
        if (org.apache.commons.collections4.CollectionUtils.isNotEmpty(list)){
            BigDecimal sumGiftGold= list.stream().map(x-> x.getGiftGold().multiply(new BigDecimal(x.getQuantity()))).reduce(BigDecimal.ZERO, BigDecimal::add);
            appAnchorVO.setReceivingGifts(sumGiftGold);
        }
        return appAnchorVO;
    }

    @Override
    public void addAnchors(List<H2Anchor> anchors) {
        this.saveBatch(anchors);
    }

    @Override
    public List<Long> existAnchorByUserIds(List<Long> userIds) {
        LambdaQueryWrapper<H2Anchor> qw = new LambdaQueryWrapper<>();
        qw.select(H2Anchor::getUserId);
        qw.in(H2Anchor::getUserId, userIds);
        List<H2Anchor> anchors = list(qw);
        return anchors == null ? null : anchors.stream().map(H2Anchor::getUserId).collect(Collectors.toList());
    }

    @Override
    public H2Anchor checkAnchorsAndReturn(Long userId) {
        H2Anchor h2Anchor = baseMapper.queryAnchorByUserId(userId);
        if (null == h2Anchor) {
            throw new QysException(AnchorMessageEnum.请先申请主播);
        }
        if (1 == h2Anchor.getAnchorStatus()) {
            throw new QysException(AnchorMessageEnum.主播已被冻结);
        }
        return h2Anchor;
    }

    @Override
    public boolean edit(H2AnchorEditDTO dto) {
        H2Anchor h2Anchor =null;
        if (null == dto.getUserRandomId()){
            h2Anchor = baseMapper.queryAnchorByUserId(SecurityUtils.getUserId());
        }else {
            h2Anchor = baseMapper.selectById(dto.getUserRandomId());
        }

        if (null == h2Anchor) {
            throw new QysException(AnchorMessageEnum.请先申请主播);
        }
        //修改主播信息
        h2Anchor.setCarBefore(StringUtils.isNotBlank(dto.getCarBefore())?dto.getCarBefore():h2Anchor.getCarBefore());
        h2Anchor.setCarAfter(StringUtils.isNotBlank(dto.getCarAfter())?dto.getCarAfter():h2Anchor.getCarAfter());
        h2Anchor.setCarNum(StringUtils.isNotBlank(dto.getCarNum())?dto.getCarNum():h2Anchor.getCarNum());
        h2Anchor.setEmail(StringUtils.isNotBlank(dto.getEmail())?dto.getEmail():h2Anchor.getEmail());
        h2Anchor.setPhone(StringUtils.isNotBlank(dto.getPhone())?dto.getPhone():h2Anchor.getPhone());
        h2Anchor.setAnchorName(StringUtils.isNotBlank(dto.getAnchorName())?dto.getAnchorName():h2Anchor.getAnchorName());

        updateById(h2Anchor);
        //修改用户信息
        H2AppUser user = new H2AppUser();
        BeanUtils.copyProperties(dto, user);
        user.setUserRandomId(null);
        if (null != dto.getBirthday()) {
            user.setAge(LocalDate.now().getYear() - user.getBirthday().getYear());
        }
        appUserService.updateById(user);
        return true;
    }

    @Override
    public List<H2Anchor> getALl() {
        LambdaQueryWrapper<H2Anchor> qw = new LambdaQueryWrapper<>();
        qw.eq(H2Anchor::getIsDelete,0);
        return list(qw);
    }

    @Override
    public void sendMail(String emailAddress) {
        // 生成一个六位的随机整数
        int min = 100000;
        int max = 999999;
        int randomNumber = new Random().nextInt(max - min + 1) + min;
        String msg=languageTextService.getByLangAndTypeId("email_code_temp", LanguageEnum.EN_US.getLang());
        if (org.apache.commons.lang3.StringUtils.isNotBlank(msg)){
            HashMap params =new HashMap();
            params.put("code",randomNumber);
            ExpressionParser parser = new SpelExpressionParser();
            TemplateParserContext parserContext = new TemplateParserContext();
            msg = parser.parseExpression(msg,parserContext).getValue(params, String.class);
        }
        if (msg==null) {
            msg=MessageUtils.message("sms.template");
            msg = String.format(msg, randomNumber);
            //发送短信
        }

        //发送短信
        MailM mailM = new MailM();
        mailM.setTitle(MessageUtils.message("shop.mail.title"));
        mailM.setMsg(msg);
        mailM.setToUsers(Lists.newArrayList(emailAddress));

        asyncMailClient.send(mailM);
        redisCache.setCacheObject("mail:anchorApply:"+ emailAddress, randomNumber, 5L, TimeUnit.MINUTES);
    }

    /**
     * 主播收益统计
     *
     * @param userId 用户id
     * @return
     */
    @Override
    public AnchorIncomeInformationVO incomeInformation(Long userId) {

        AnchorIncomeInformationVO vo = new AnchorIncomeInformationVO();

        //总收益
        vo.setTotalRevenue(this.totalLiveRevenue(userId));

        //礼物总收益
        List<FinanceUserAccountDetail> details2 = financeUserAccountDetailMapper.selectList(this.getBaseWrapper(userId, Lists.newArrayList( "lv_gg"), false));
        vo.setGrossGiftProceeds(this.sumUp(details2));

        //带货总收益
        List<FinanceUserAccountDetail> details3 = financeUserAccountDetailMapper.selectList(this.getBaseWrapper(userId, Lists.newArrayList( "yh_ag"), false));
        vo.setGrossProceedsFromSales(this.sumUp(details3));

        //当日总收益
        List<FinanceUserAccountDetail> details4 = financeUserAccountDetailMapper.selectList(this.getBaseWrapper(userId, Lists.newArrayList( "yh_ag", "lv_bs", "lv_gg"), true));
        vo.setTotalIncomeOfTheDay(this.sumUp(details4));

        //当日礼物收益
        List<FinanceUserAccountDetail> details5 = financeUserAccountDetailMapper.selectList(this.getBaseWrapper(userId, Lists.newArrayList( "lv_gg"), true));
        vo.setDayGiftIncome(this.sumUp(details5));

        //当日带货收益
        List<FinanceUserAccountDetail> details6 = financeUserAccountDetailMapper.selectList(this.getBaseWrapper(userId, Lists.newArrayList( "yh_ag"), true));
        vo.setDaySalesRevenue(this.sumUp(details6));

        return vo;
    }


    @Override
    public BigDecimal totalLiveRevenue(Long userId){
        List<FinanceUserAccountDetail> total = financeUserAccountDetailMapper.selectList(this.getBaseWrapper(userId, Lists.newArrayList("yh_ag", "lv_bs", "lv_gg"), false));
        return this.sumUp(total);
    }

    @Override
    public AnchorRewardConfig cumulativeIncomeBonus(Long userId) {

        //计算直播总计收益
        BigDecimal totalLiveRevenue = this.totalLiveRevenue(userId);
        if(totalLiveRevenue.equals(BigDecimal.ZERO)){
            return null;
        }

        //匹配奖励金额
        List<AnchorRewardConfig> configList = anchorRewardConfigMapper.selectList(Wrappers.<AnchorRewardConfig>lambdaQuery()
                .eq(AnchorRewardConfig::getAwardType, 2)
                .le(AnchorRewardConfig::getAwardCondition, totalLiveRevenue)
                .orderByDesc(AnchorRewardConfig::getAwardCondition)
                .last("limit 1")
        );

        //根据匹配到的奖金返回值
        if(!CollectionUtils.isEmpty(configList)){
            AnchorRewardConfig rewardConfig = configList.get(0);
            //判断该用户是否领取过本阶段奖励
            int count = anchorRewardConfigMapper.rewardJudgment(rewardConfig.getConId(), userId, false);
            if(count > 0){
                return null;
            } else {
                return rewardConfig;
            }
        }
        return null;

    }

    @Override
    public void keepRewardRecords(Long conId, Long userId) {
        anchorRewardConfigMapper.keepRecords(conId, userId);
    }

    @Override
    public SettlementDataVO salesMissionDetails(Long userId, Long anchorSellTaskId) {

        H2Anchor h2Anchor = this.checkAnchorsAndReturn(userId);

        AnchorLivesSession livesSession = livesSessionMapper.selectOne(Wrappers.<AnchorLivesSession>lambdaQuery()
                .eq(AnchorLivesSession::getAnchorId, h2Anchor.getId())
                .eq(AnchorLivesSession::getAnchorSellTaskId, anchorSellTaskId));

        //获取本场主播的用户信息
        H2AppUser appUser = ih2AppUserService.getById(userId);

        SettlementDataVO settlementDataVO = new SettlementDataVO();
        BeanUtils.copyProperties(livesSession, settlementDataVO);
        settlementDataVO.setAnchorName(appUser.getNickName());
        settlementDataVO.setAnchorAvatar(appUser.getAvatar());

        //任务描述
        AnchorSellTask anchorSellTask = anchorSellTaskMapper.selectById(anchorSellTaskId);
        ShopSellTask shopSellTask = shopSellTaskMapper.selectById(anchorSellTask.getShopSellTaskId());
        settlementDataVO.setTaskIntroduction(shopSellTask.getTaskInfo());

        //底薪
        String basicSalary = h2Anchor.getBasicSalary();
        if(StringUtils.isNotBlank(basicSalary)){
            BigDecimal basedOnTime = getValueBasedOnTime(livesSession.getLivesDuration(), basicSalary);
            settlementDataVO.setBasicSalary(basedOnTime);
        }

        //礼物提成
        BigDecimal giftRatio = h2Anchor.getGiftRatio();
        if(giftRatio != null){
            settlementDataVO.setGiftCommission(livesSession.getGoldNum().multiply(giftRatio));
        }

        //订单提成
        List<ShopOrderSku> shopOrderSkus = shopOrderSkuMapper.selectList(Wrappers.<ShopOrderSku>lambdaQuery()
                .select(ShopOrderSku::getId)
                .eq(ShopOrderSku::getTaskId, livesSession.getId())
                .notIn(ShopOrderSku::getOrderStatus,OrderStatus.CANCELED, OrderStatus.WAIT_PAY)
        );
        if(!CollectionUtils.isEmpty(shopOrderSkus)){
            List<Long> orderId = shopOrderSkus.stream().map(ShopOrderSku::getId).toList();
            List<ShopOrderSettlementInfo> infos = shopOrderSettlementInfoMapper.selectList(Wrappers.<ShopOrderSettlementInfo>lambdaQuery()
                    .select(ShopOrderSettlementInfo::getAnchorProfit)
                    .in(ShopOrderSettlementInfo::getOrderId, orderId));
            BigDecimal total = infos.stream().map(ShopOrderSettlementInfo::getAnchorProfit).reduce(BigDecimal.ZERO, BigDecimal::add);
            settlementDataVO.setOrderIncome(total);
        }

        return settlementDataVO;
    }

    @Override
    public H2AnchorVO sellingInformation(Long id) {
        return baseMapper.getAnchorSellingInformation(id);
    }

    /**
     * 根据直播时长匹配底薪
     * @param livesDuration  直播时长
     * @param basicSalary  底薪配置
     * @return
     */
    public BigDecimal getValueBasedOnTime(Integer livesDuration, String basicSalary) {
        JSONObject jsonObject = JSONObject.parseObject(basicSalary);

        BigDecimal result = BigDecimal.ZERO;
        for (String key : jsonObject.keySet()) {
            if (Integer.parseInt(key) <= livesDuration) {
                String val = (String) jsonObject.get(key);
                result =  new BigDecimal(val);
            }
        }

        return result;
    }


    @Override
    public void incomeRankingAward(int type) {
        //查询所有直播过的主播的用户id，获取每个用户的收益
        List<AnchorLivesRoom> livesRooms = anchorLivesRoomService.list();
        Map<Long, BigDecimal> map = Maps.newHashMap();
        for (AnchorLivesRoom livesRoom : livesRooms) {
            H2AppUser user = anchorLivesRoomService.getUserByAnchorId(livesRoom.getAnchorId());
            BigDecimal income = financeUserAccountDetailMapper.getCumulativeIncome(Long.valueOf(user.getId()), Lists.newArrayList("yh_ag", "lv_bs", "lv_gg"), type == 5 ? 2 : 3);
            if(income == null || income.equals(BigDecimal.ZERO)){
                //排除没有收益的
                continue;
            }
            map.put(Long.valueOf(user.getId()), income);
        }

        //查询奖励配置
        List<AnchorRewardConfig> configList = anchorRewardConfigMapper.selectList(Wrappers.<AnchorRewardConfig>lambdaQuery()
                .eq(AnchorRewardConfig::getAwardType, type)
                .orderByAsc(AnchorRewardConfig::getAwardCondition)
        );

        //根据名次返现
        List<Long> topUsers = this.getTopUsers(map, configList.size());
        log.info("topUsers:{}",topUsers);
        for (int i = 0; i < topUsers.size(); i++) {
            AnchorRewardConfig config = configList.get(i);
            //判断是否领取过该阶段奖励
            int rewarded = anchorRewardConfigMapper.rewardJudgment(config.getConId(), topUsers.get(i), true);
            if(rewarded > 0){
                continue;
            }
            FinancePayDTO payDTO = new FinancePayDTO();
            payDTO.setUserId(topUsers.get(i));
            payDTO.setBusinessType(type == 5 ? AccountBusinessTypeEnum.EARNINGS_DAY_RANKING_REWARDS : AccountBusinessTypeEnum.EARNINGS_MONTHLY_RANK_BONUS);
            payDTO.setAmountIncurred(config.getAwardAmount());
            payDTO.setBusinessNo(BusinessNoUtil.get(type == 5 ? AccountBusinessTypeEnum.EARNINGS_DAY_RANKING_REWARDS : AccountBusinessTypeEnum.EARNINGS_MONTHLY_RANK_BONUS));
            payDTO.setDescription("主播收益排名奖励");
            financeBusinessService.pay(payDTO);
            if (payDTO.getSuccess()) {
                anchorRewardConfigMapper.keepRecords(config.getConId(), topUsers.get(i));
                log.info("主播收益排名奖励成功, 奖励配置id:{}，userId:{}", config.getConId(), topUsers.get(i));
            } else {
                log.info("主播收益排名奖励失败, 奖励配置id:{}，userId:{}，原因：{}", config.getConId(), topUsers.get(i), payDTO.getMessage());
            }
        }
    }


    /**
     * @param map   用户收益集合
     * @param size  名次总数
     * @return
     */
    private List<Long> getTopUsers(Map<Long, BigDecimal> map, int size) {
        List<Map.Entry<Long, BigDecimal>> list = new ArrayList<>(map.entrySet());

        // 根据收入降序排序
        list.sort((o1, o2) -> o2.getValue().compareTo(o1.getValue()));

        // 截取前三名的用户ID
        List<Long> topList = new ArrayList<>();
        for (int i = 0; i < Math.min(size, list.size()); i++) {
            topList.add(list.get(i).getKey());
        }

        return topList;
    }

    private LambdaQueryWrapper<FinanceUserAccountDetail> getBaseWrapper(Long userId, List<String> code, boolean today){
        LambdaQueryWrapper<FinanceUserAccountDetail> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.select(FinanceUserAccountDetail::getAmountIncurred)
                .eq(FinanceUserAccountDetail::getUserId, userId)
                .eq(FinanceUserAccountDetail::getInOut, "1")
                .between(today, FinanceUserAccountDetail::getPayDate, LocalDate.now().atStartOfDay(), LocalDate.now().atTime(LocalTime.MAX))
                .in(FinanceUserAccountDetail::getCode, code);
        return queryWrapper;
    }

    private BigDecimal sumUp(List<FinanceUserAccountDetail> details){
        if(!CollectionUtils.isEmpty(details)){
            return details.stream()
                    .map(FinanceUserAccountDetail::getAmountIncurred)
                    .reduce(BigDecimal.ZERO, BigDecimal::add);
        }
        return BigDecimal.ZERO;
    }
}

